package org.epanetgrid.otimizacao;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.epanetgrid.otimizacao.simulation.SimulacaoNaoConvergeException;


/**
 * Implementa os m�todos comuns a todas as subclasses de OtimizadorObservable
 * @author vinicius
 *
 */
public abstract class AbstractOtimizadorObservable implements OtimizadorObservable {
	private List<OtimizadorObserver> observers = new LinkedList<OtimizadorObserver>();
	private Thread thread;
	private long count = 0;
	private boolean started = false;
	private boolean stoped;

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#start()
	 */
	public void start() {
		if (!started) {
			started = true;
			stoped = false;
			thread = new Thread("OtimizadorStart" + count++) {
				public void run() {
					try{
						execute();
					}catch (SimulacaoNaoConvergeException e) {
					}
				}
			};
			thread.start();
		}
	}
	
	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#start()
	 */
	public void restart() {
		System.out.println("Restart chamado: "+started+"="+this);
		if (started && !isStoped()) {
			System.out.println("Restartado");
			stoped = false;
			thread = new Thread("OtimizadorStart" + count++) {
				public void run() {
					stoped = false;
					try{	
						reexecute();
					}catch (SimulacaoNaoConvergeException e) {
					}
				}
			};
			thread.start();
		}
	}

	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#stop()
	 */
	public void stop() {
		System.out.println("Stop: "+this);
		if (started) {
			stoped = true;
			Thread stopThread = new Thread("OtimizadorStop" + count++) {
				public void run() {
					try {
						forcedStop();
					} catch (ThreadDeath e1) {}
					
				}
			};
			stopThread.start();
			notifyObservers(new OtimizadorEventObject(this, null, OtimizadorEvent.FINAL));
		}
		System.out.println("isStoped:: "+this.isStoped());
	}
	
	/* (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#pause()
	 */
	public void pause() {
		System.out.println("Pause chamado");
		if (started) {
			System.out.println("Chamando force stop");
			forcedStop();
//			Thread stopThread = new Thread("OtimizadorStop" + count++) {
//				public void run() {
//					try {
//						forcedStop();
//					} catch (Throwable e1) {}
//					
//				}
//			};
//			stopThread.start();
			notifyObservers(new OtimizadorEventObject(this, null, OtimizadorEvent.PAUSE));
		}
	}

	/**
	 * For�a o stop da thread 2x
	 * TODO
	 */
	private synchronized void forcedStop() {
		System.out.println("stoped: "+stoped);
//		if (!stoped) {
//			stoped = true;
			try {
				thread.interrupt();
				thread.stop();
			} catch (Throwable e) {
				e.printStackTrace();
				try {
					thread.interrupt();
					thread.stop();
				} catch (Throwable e1) {
				}
			}
//		}
	}

	/**
	 * Subclasses devem implementar este m�todo. � chamado pelo m�todo start
	 */
	protected abstract void execute();
	
	/**
	 * Subclasses devem implementar este m�todo. � chamado pelo m�todo restart
	 */
	protected abstract void reexecute();

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#addObserver(org.smartpumping.otimizacao.OtimizadorObserver)
	 */
	public synchronized void addObserver(OtimizadorObserver observer) {
		observers.add(observer);
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#deleteObserver(org.smartpumping.otimizacao.OtimizadorObserver)
	 */
	public synchronized void deleteObserver(OtimizadorObserver observer) {
		observers.remove(observer);
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#deleteObservers()
	 */
	public synchronized void deleteObservers() {
		observers.clear();
	}

	/*
	 * (non-Javadoc)
	 * @see org.smartpumping.otimizacao.OtimizadorObservable#getObservers()
	 */
	public synchronized Collection<OtimizadorObserver> getObservers() {
		return Collections.unmodifiableCollection(observers);
	}

	/**
	 * 
	 * @param event
	 */
	protected synchronized void notifyObservers(OtimizadorEvent event) {
		List<OtimizadorObserver> list = new LinkedList<OtimizadorObserver>(observers);
		for (Iterator it = list.iterator(); it.hasNext();) {
			((OtimizadorObserver) it.next()).update(event);
		}
	}

	/**
	 * 
	 * @return
	 */
	protected OtimizadorObservable getMySelf() {
		return this;
	}

	public boolean isStoped() {
		return stoped;
	}

}
